#pragma  once
#include "common_include.h"
#include <wincrypt.h>

class PubKey {
protected:
	BYTE	*key;
	int		keyLen;
	int		e;
	int		capa;

public:
	PubKey(void) { key = NULL; capa = 0; }
	~PubKey() { UnSet(); }

	void Set(BYTE *_key, int len, int _e, int _capa) {
		UnSet(); e = _e; capa = _capa; key = new BYTE [keyLen=len]; memcpy(key, _key, len);
	}
	void UnSet(void) {
		delete [] key; key = NULL; capa = 0;
	}
	const BYTE *Key(void) { return key; }
	int KeyLen(void) { return keyLen; }
	int Exponent(void) { return e; }
	BOOL KeyBlob(BYTE *blob, int maxLen, int *len) {
		if ((*len = KeyBlobLen()) > maxLen) return FALSE;
		/* PUBLICSTRUC */	blob[0] = PUBLICKEYBLOB; blob[1] = CUR_BLOB_VERSION;
		*(WORD *)(blob+2) = 0; *(ALG_ID *)(blob+4) = CALG_RSA_KEYX;
		/* RSAPUBKEY */		memcpy(blob+8, "RSA1", 4);
		*(DWORD *)(blob+12) = keyLen * 8; *(int *)(blob+16) = e;
		/* PUBKEY_DATA */	memcpy(blob+20, key, keyLen);
		return	TRUE;
	}
	int KeyBlobLen(void) { return keyLen + 8 + 12; /* PUBLICKEYSTRUC + RSAPUBKEY */ }
	void SetByBlob(BYTE *blob, int _capa) {
		UnSet();
		keyLen = *(int *)(blob+12) / 8;
		key = new BYTE [keyLen];
		memcpy(key, blob+20, keyLen);
		e = *(int *)(blob+16);
		capa = _capa;
	}
	int Capa(void) { return capa; }
};




struct HostSub {
	char	userName[MAX_NAMEBUF];
	char	hostName[MAX_NAMEBUF];
	ULONG	addr;
	int		portNo;
};


struct Host {
	HostSub	hostSub;
	char	nickName[MAX_NAMEBUF];
	char	groupName[MAX_NAMEBUF];
	ULONG	hostStatus;
	time_t	updateTime;
	int		priority;
	int		refCnt;
	PubKey	pubKey;
	int		cryptSpec;

	Host(void) { refCnt = 0; }
	~Host() { refCnt = 0; }
	int	RefCnt(int cnt=0) { return refCnt += cnt; }
};

class THosts {
public:
	enum Kind { NAME, ADDR, NAME_ADDR, MAX_ARRAY };
	BOOL enable[MAX_ARRAY];

protected:
	int		hostCnt;
	Host	**array[MAX_ARRAY];
	Host	*Search(Kind kind, HostSub *hostSub, int *insertIndex=NULL);
	int		Cmp(HostSub *hostSub1, HostSub *hostSub2, Kind kind);

public:
	THosts(void);
	~THosts();

	void	Enable(Kind kind, BOOL _enable) { enable[kind] = _enable; }
	BOOL	AddHost(Host *host);
	BOOL	DelHost(Host *host);
	int		HostCnt(void) { return hostCnt; }
	Host	*GetHost(int index, Kind kind=NAME) { return array[kind][index]; }
	Host	*GetHostByName(HostSub *hostSub) { return enable[NAME] ? Search(NAME, hostSub) : NULL; }
	Host	*GetHostByAddr(HostSub *hostSub) { return enable[ADDR] ? Search(ADDR, hostSub) : NULL; }
	Host	*GetHostByNameAddr(HostSub *hostSub) { return enable[NAME_ADDR] ? Search(NAME_ADDR, hostSub) : NULL; }
	int		PriorityHostCnt(int priority, int range=1);
};
